home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- **
- ** Copyright 1996, 1997 by Ernest R. Schreurs.
- ** All rights reserved.
- ** Use of this source code is allowed under the following conditions:
- ** You must inform people that you based your work on this stuff.
- ** If you charge a fee in any form for your product, you must inform people
- ** that this stuff is available free of charge.
- ** Refer to the documentation for more information.
- **
- *****************************************************************************/
- #define MODULE "WAV2CAS.C"
- /*****************************************************************************
- ** NAME: WAV2CAS.C
- **
- ** Author : Ernest R. Schreurs
- ** Date : May 1, 1997
- ** Release : 01.00
- **
- ** Description : This program will convert a .wav sound file to
- ** a format known as the .cas format. It is assumed
- ** that the wav file contains a sample of a Classic Atari
- ** cassette tape. This program converts the FSK sounds to
- ** the data they are representing.
- **
- ** Amiga port by Wojciech Pasiecznik (voydial@wp.pl), Feb. 14, 2002.
- ** Few additional changes:
- **
- ** - Control Z check is replaced by the Control C (including comments),
- ** - title is a little changed ;).
- **
- *****************************************************************************/
-
- /*****************************************************************************
- == INCLUDE FILES
- *****************************************************************************/
- #include <stdio.h> /* For printf() and gets() */
- #include <ctype.h> /* For isalnum() and toupper() */
- #include <stdlib.h> /* For the exit function */
- #include <string.h> /* String and memory stuff */
-
- /*****************************************************************************
- == DEFINED SYMBOLS
- *****************************************************************************/
-
- #ifndef FALSE
- #define FALSE 0
- #endif
- #ifndef TRUE
- #define TRUE 1
- #endif
-
- #ifndef NULL
- #define NULL 0
- #endif
- #define PATH_LEN 128 /* Maximum path length */
-
- #define BUF_LEN 80 /* fgets buffer length */
- #define SUCCESS 1 /* Success is non-zero */
- #define FAILURE 0 /* Failure is zero */
-
- /*
- ** The PCM data is read from the wave file into a PCM buffer.
- ** The size of the buffer that is allocated is equal to the value defined
- ** below. It must be an even value. The buffer is replenished when half
- ** of the buffer is empty. Therefore we also need to know what half of
- ** the buffer size is. Make sure these values agree, if changing one,
- ** always change the other too.
- */
- #define PCM_BUF_LEN 512 /* Size of PCM data buffer */
- #define PCM_BUF_HALF 256 /* Exactly half of above value */
- #define SAMPLE_CNT_TBL_LEN 3000L /* Size of sample count table */
-
- /*
- ** A tape record starts with a Pre-Record Write Tone.
- ** Then we find bytes, usually 132, each starting with a startbit,
- ** eight data bits, lsb first, followed by a stopbit.
- ** This is all coded in mark and space tones, as defined below.
- */
- #define FSK_MARK 1 /* Mark tone represents a 1 */
- #define FSK_SPACE 0 /* Space tone represents a 0 */
- #define FSK_1 1 /* A 1 bit is a mark */
- #define FSK_0 0 /* A 0 bit is a space */
- #define FSK_PRWT 1 /* PRWT tone is a mark */
- #define FSK_STARTBIT 0 /* Startbit is a space */
- #define FSK_STOPBIT 1 /* Stopbit is a mark */
-
- /*
- ** Definitions for the mark and space tone frequencies.
- */
- #define FSK_TONE_MARK 5327 /* Frequency of mark tone */
- #define FSK_TONE_SPACE 3995 /* Frequency of space tone */
-
- /*****************************************************************************
- == MACRO DEFINITIONS
- *****************************************************************************/
- /*
- ** Macro for casting stuff to requirements of stupid
- ** standard library functions.
- */
-
- #define FGETS( buf, buf_len, file_ptr ) \
- (void *)fgets( (char *)buf, (int)buf_len, (FILE *)file_ptr )
-
- #define STRLEN( str ) \
- strlen( (const char *)(str) )
-
- /*
- ** Macro for getting input from the terminal,
- ** allowing the user to exit with either control C or
- ** inputting the string ^C to indicate intention of
- ** terminating the program.
- */
- #define GET_BUF() \
- { \
- if ( FGETS( buf, BUF_LEN, stdin ) == NULL ) \
- { \
- printf( "Terminated by ^C\n" ); \
- exit(0); \
- } \
- if ( memcmp( buf, "^C", 2 ) == 0 || memcmp( buf, "^c", 2 ) == 0 ) \
- { \
- printf( "Terminated by ^C\n" ); \
- exit(0); \
- } \
- }
-
- #define PRINT( lst ) \
- { \
- if( diagnostics ) \
- { \
- printf lst; \
- } \
- }
-
- /*****************************************************************************
- == TYPE and STRUCTURE DEFINITIONS
- *****************************************************************************/
- typedef unsigned char bool; /* Boolean value */
- typedef unsigned char ubyte; /* Exactly eight bits, unsigned */
- typedef short int16; /* At least 16 bits, signed */
- typedef unsigned short uint16; /* At least 16 bits, unsigned */
- typedef long int32; /* At least 32 bits, signed */
- typedef unsigned long uint32; /* At least 32 bits, unsigned */
-
- /*
- ** Cassette file header.
- */
-
- typedef struct
- {
- ubyte cas_record_id[4]; /* Cassette record type */
- ubyte cas_len_lo; /* Record length low byte */
- ubyte cas_len_hi; /* Record length high byte */
- ubyte cas_aux1; /* Type dependant data */
- ubyte cas_aux2; /* Type dependant data */
- ubyte cas_data[8192]; /* Data */
- } cas_blk;
-
- /*
- ** fsk_cnt stream. The duration of each mark and space is counted in
- ** pairs, since they alternate.
- */
-
- typedef struct
- {
- uint32 sample_pos; /* Position of sample in .wav file */
- uint32 sample_cnt_mark; /* Number of samples in mark state */
- uint32 sample_cnt_space; /* Number of samples in space state */
- } sample_cnt_blk;
-
- /*****************************************************************************
- == IMPORTED VARIABLES
- *****************************************************************************/
- /*****************************************************************************
- == LOCAL ( HIDDEN ) VARIABLES
- *****************************************************************************/
- static FILE * wav_file; /* Wave file */
- static FILE * fsk_file; /* FSK intermediate file */
- static FILE * hex_file; /* HEX intermediate file */
- static FILE * cas_file; /* Cassette image file */
-
- static cas_blk cas_rec; /* The cassette record buffer */
-
- static uint32 cnt_cur; /* Current period count, rounded */
- static uint32 cnt_next; /* Next period count */
- static uint32 cnt_prev; /* Previous period count */
- static uint32 cnt_total; /* Total sample count */
- static uint32 cnt_val; /* Current period actual count */
-
- static bool diagnostics; /* Print diagnostic data */
- static bool fsk; /* Write FSK table file */
- static bool fsk_print_first; /* Writing FSK first line */
- static uint32 sample_cnt_high; /* High count limit for mark tone */
- static uint32 sample_cnt_irg; /* Count limit for IRG detection */
- static uint32 sample_cnt_low; /* Low count limit for mark tone */
- static uint32 sample_cnt_bit; /* Expected sample count for one bit*/
- static uint32 sample_cnt_bit_limit; /* Low limit count for one bit */
- static uint32 sample_cnt_minimum; /* Minimum count for complete period*/
- static sample_cnt_blk * sample_cnt_tbl; /* Count table */
- static uint32 sample_tbl_ndx; /* Count table index */
- static uint16 sample_tbl_level; /* Current level being counted */
-
- static ubyte pcm[PCM_BUF_LEN]; /* Buffer with samples */
- static uint32 pcm_bytes; /* Number of bytes read into buffer */
- static uint32 pcm_cnt; /* Buffer byte count */
- static uint32 pcm_ck_len; /* Length of PCM data chunk in file */
- static uint32 pcm_level_previous; /* Previous sample level */
- static bool pcm_level_rising; /* Rising / falling */
- static uint32 pcm_ndx; /* Buffer index pointer */
- static uint32 pcm_ndx_end; /* Buffer end pointer to free space */
-
- static uint32 printed_bytes; /* Number of bytes printed on line */
- static uint32 sample_rate; /* Sampling rate */
-
- /*****************************************************************************
- == EXPORTED VARIABLES
- *****************************************************************************/
- /*****************************************************************************
- == IMPORTED FUNCTIONS
- *****************************************************************************/
- /*****************************************************************************
- == LOCAL ( HIDDEN ) FUNCTIONS
- *****************************************************************************/
- static void cleanup( void );
- static uint32 period_sample_cnt( void );
- static void process_cnt( uint32 cnt, uint16 level );
- static uint32 process_header( void );
- static void process_record( void );
- static void replenish_buffer( void );
- static void usage( char * cmd );
- static uint32 wav2fsk( void );
-
- /*****************************************************************************
- == EXPORTED FUNCTIONS
- *****************************************************************************/
- int main(); /* Normal entry point to it all */
-
- /*****************************************************************************
- == LOCAL ( HIDDEN ) FUNCTIONS
- *****************************************************************************/
-
- /*****************************************************************************
- ** NAME: cleanup()
- **
- ** PURPOSE:
- ** Cleanup any mess that was created.
- **
- ** DESCRIPTION:
- ** This function will attempt to close all open files and
- ** free allocated memory.
- **
- ** INPUT:
- ** - The file pointers and paths are used.
- **
- ** OUTPUT:
- ** The function returns nothing.
- **
- */
-
- static void cleanup( void )
- {
- if( wav_file )
- {
- fclose( wav_file );
- }
- if( fsk_file )
- {
- fclose( fsk_file );
- }
- if( hex_file )
- {
- fclose( hex_file );
- }
- if( cas_file )
- {
- fclose( cas_file );
- }
-
- if( sample_cnt_tbl )
- free( (void *)sample_cnt_tbl );
- return;
- }
-
- /*****************************************************************************
- ** NAME: period_sample_cnt()
- **
- ** PURPOSE:
- ** Count the number of samples within one period.
- **
- ** DESCRIPTION:
- ** This function will count the samples between two period tops.
- **
- ** INPUT:
- ** Nothing.
- ** Data is taken from the pcm buffer.
- **
- ** OUTPUT:
- ** Sets the sample count to the number of samples within one period.
- ** If this is zero, there are no more samples.
- ** Prints results.
- ** Returns SUCCESS if data converted successfully.
- ** Returns FAILURE if some error occurred.
- **
- */
-
- static uint32 period_sample_cnt( void )
- {
-
- /*
- ** What was the current sample count, will now be the previous value.
- ** What was the next sample count, will now be the current value, which
- ** will later be rounded by comparing it with the new previous and next
- ** sample counts.
- ** What was the actual next sample count will be recorded as the value of
- ** the sample counter for purposes of timing.
- ** Determine the count for the next sample count.
- */
- cnt_prev = cnt_val;
- cnt_cur = cnt_next;
- cnt_val = cnt_next;
- cnt_next = 0;
-
- while( pcm_bytes )
- {
-
- /*
- ** Replenish buffer if beyond the critical mark.
- */
- if( pcm_ndx >= PCM_BUF_HALF )
- replenish_buffer();
-
- /*
- ** For better difference between mark and space, we count one complete
- ** period, starting at one top, until the top one period away.
- ** We start out with a falling level, back to rising, and when the level
- ** stops rising, we have counted one complete period. In order to eliminate
- ** noise, the number of samples must be beyond a treshold. This by itself
- ** does not eliminate noise, but it eliminates low period counts.
- */
- if( pcm_level_rising )
- { /* Level rising */
- if( pcm[pcm_ndx] <= pcm_level_previous ) /* At the top? */
- {
- pcm_level_rising = FALSE;
- pcm_level_previous = 255;
- if( cnt_next > sample_cnt_minimum ) /* Is it a period?*/
- break;
- }
- else
- pcm_level_previous = pcm[pcm_ndx];
- } /* end if level rising */
- else
- { /* Level falling */
- if( pcm[pcm_ndx] >= pcm_level_previous ) /* At the bottom? */
- {
- pcm_level_rising = TRUE;
- pcm_level_previous = 0;
- }
- else
- pcm_level_previous = pcm[pcm_ndx];
- } /* end else if level rising */
-
- /*
- ** Count the number of samples within this period.
- */
- cnt_next++;
- pcm_ndx++;
- pcm_bytes--;
- }
-
- /*
- ** Allow for sampling timing differences. If previous and next value
- ** agree, the current sample is made to be the same value. Otherwise,
- ** it remains the sample count value as counted.
- */
- if( ( cnt_val == sample_cnt_low ) && ( cnt_next >= sample_cnt_low ) )
- if( cnt_prev > sample_cnt_low )
- cnt_cur = sample_cnt_low + 1;
- if( ( cnt_val == sample_cnt_low ) && ( cnt_next <= sample_cnt_low ) )
- if( cnt_prev < sample_cnt_low )
- cnt_cur = sample_cnt_low - 1;
-
- return( SUCCESS );
- }
-
- /*****************************************************************************
- ** NAME: process_cnt()
- **
- ** PURPOSE:
- ** The sample count is used to build a table of the duration of each
- ** mark and space tone. Since this is fsk data, when one stops, the
- ** other starts, so they are counted in pairs.
- **
- ** DESCRIPTION:
- ** The samples are added to the sample count table. When there is a
- ** complete record in the table, we can output it to the .cas file.
- **
- ** INPUT:
- ** - The number of samples to be represented.
- ** - The level represented by the samples.
- **
- ** OUTPUT:
- ** Data is added to the table.
- ** The function returns nothing.
- **
- */
-
- static void process_cnt( cnt, level )
- uint32 cnt; /* Number of samples of this level */
- uint16 level; /* Interpreted level of signal */
- {
-
- /*
- ** If the level is the same as the previous level, we add the count to the
- ** running total. If the level is not the same, we start a new running total.
- ** If the new level is a space, start counting in the space counter. If the
- ** level is a mark, we must increment the buffer pointer, and then we can
- ** start counting in the mark counter.
- */
-
- if( level == sample_tbl_level )
- {
- if( level == FSK_SPACE )
- sample_cnt_tbl[sample_tbl_ndx].sample_cnt_space += cnt;
- else
- sample_cnt_tbl[sample_tbl_ndx].sample_cnt_mark += cnt;
- }
- else
- {
- sample_tbl_level = level;
- if( level == FSK_SPACE )
- {
- sample_cnt_tbl[sample_tbl_ndx].sample_cnt_space = cnt;
-
- /*
- ** If this mark was long enough to be recognized as an IRG or PRWT,
- ** we can start interpreting the count values as bits and bytes.
- */
- if( sample_cnt_tbl[sample_tbl_ndx].sample_cnt_mark > sample_cnt_irg )
- {
- process_record();
- }
- }
- else
- {
- if( sample_tbl_ndx == SAMPLE_CNT_TBL_LEN ) /* Table full? */
- process_record();
- sample_tbl_ndx++;
- sample_cnt_tbl[sample_tbl_ndx].sample_cnt_mark = cnt;
- sample_cnt_tbl[sample_tbl_ndx].sample_pos = cnt_total;
- }
- }
-
- cnt_total += cnt;
-
- return;
- }
-
- /*****************************************************************************
- ** NAME: process_header()
- **
- ** PURPOSE:
- ** Process the data from the header of the .wav file and store
- ** relevant information.
- **
- ** DESCRIPTION:
- ** This function will read the relevant data about the .wav file
- ** and store it.
- **
- ** INPUT:
- ** Nothing.
- ** Data is read from the wave file.
- **
- ** OUTPUT:
- ** Prints results.
- ** Stores data related to the format and contents of the wave file.
- ** Returns SUCCESS if header was processed successfully.
- ** Returns FAILURE if some error occurred.
- **
- */
-
- static uint32 process_header( void )
- {
- uint16 bits_sample; /* Sample size */
- uint32 bytes; /* Number of bytes read */
- uint16 channels; /* Number of channels */
- uint32 ck_len; /* Chunk length */
- uint32 fi_len; /* File length */
- uint16 fmt_tag; /* Format tag */
- ubyte wav_rec[512]; /* Buffer for wave data */
-
- /*
- ** Wave files usually look like this
- **
- ** char[4] = "RIFF", long file size not including these 8 bytes,
- ** char[4] = "WAVE",
- ** char[4] = "fmt ", long wave format header size not including these 8 bytes,
- ** bunch of longs containing info about sample rate and such,
- ** char[4] = "data", long wave data size not including these 8 bytes,
- ** gobs of PCM data bytes.
- ** See below for more details.
- */
-
- /*
- ** .WAV files should begin with RIFF, followed by the size.
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( ( bytes < 4 ) || memcmp( wav_rec, "RIFF", 4 ) )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, it does not begin with \"RIFF\".\n");
- return( FAILURE );
- }
-
- /*
- ** Get the next four bytes and convert them to an uint32 value.
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( bytes < 4 )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, invalid file length.\n");
- return( FAILURE );
- }
- fi_len = (((((((uint32)wav_rec[3]) << 8 ) + wav_rec[2] ) << 8 )
- + wav_rec[1]) << 8 ) + wav_rec[0];
-
- /*
- ** Next we should find the block type "WAVE".
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( ( bytes < 4 ) || memcmp( wav_rec, "WAVE", 4 ) )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, it does not contain \"WAVE\".\n");
- return( FAILURE );
- }
-
- /*
- ** Next we should find the block type "fmt ".
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( ( bytes < 4 ) || memcmp( wav_rec, "fmt ", 4 ) )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, it does not contain \"fmt \".\n");
- return( FAILURE );
- }
-
- /*
- ** Get the chunk length.
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( bytes < 4 )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, invalid chunk length.\n");
- return( FAILURE );
- }
- ck_len = (((((((uint32)wav_rec[3]) << 8 ) + wav_rec[2] ) << 8 )
- + wav_rec[1]) << 8 ) + wav_rec[0];
-
- /*
- ** Get the format information.
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)14, wav_file );
- if( bytes < 14 )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, invalid format data.\n");
- return( FAILURE );
- }
-
- fmt_tag = (((uint16)wav_rec[1]) << 8 ) + wav_rec[0];
- channels = (((uint16)wav_rec[3]) << 8 ) + wav_rec[2];
- sample_rate = (((((((uint32)wav_rec[7]) << 8 ) + wav_rec[6] ) << 8 )
- + wav_rec[5]) << 8 ) + wav_rec[4];
-
- /*
- ** Set sample rate related variables.
- */
- if( sample_rate == 44100L )
- {
- sample_cnt_low = 10;
- sample_cnt_high = 14;
- sample_cnt_irg = 1000;
- sample_cnt_bit = 74;
- sample_cnt_bit_limit = 40;
- sample_cnt_minimum = 6;
- }
- else
- if( sample_rate == 22050 )
- {
- sample_cnt_low = 6;
- sample_cnt_high = 7;
- sample_cnt_irg = 500;
- sample_cnt_bit = 37;
- sample_cnt_bit_limit = 20;
- sample_cnt_minimum = 3;
- }
- else
- {
- fprintf(stderr, "\nSample rates other than 22.050 and 44.100 not supported.\n");
- return( FAILURE );
- }
-
- fmt_tag = (((uint16)wav_rec[1]) << 8 ) + wav_rec[0];
- if( fmt_tag != 0x0001 )
- {
- fprintf(stderr, "\nNot a PCM wave file, format 0x%.4x not supported.\n", fmt_tag);
- return( FAILURE );
- }
- if( channels != 1 )
- {
- fprintf(stderr, "\nNot a MONO wave file, stereo and multi-channel files not supported.\n");
- return( FAILURE );
- }
-
- /*
- ** Get the bits per sample information.
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)2, wav_file );
- if( bytes < 2 )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, invalid format data.\n");
- return( FAILURE );
- }
-
- bits_sample = (((uint16)wav_rec[1]) << 8 ) + wav_rec[0];
-
- if( bits_sample != 8 )
- {
- fprintf(stderr, "\nNot a sound file sampled at 8 bit, format not supported.\n");
- return( FAILURE );
- }
-
- /*
- ** Next we should find the block type "data".
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( ( bytes < 4 ) || memcmp( wav_rec, "data", 4 ) )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, it does not contain \"data\".\n");
- return( FAILURE );
- }
-
- /*
- ** Get the chunk length.
- */
- bytes = fread( (char *)wav_rec, (int)1, (int)4, wav_file );
- if( bytes < 4 )
- {
- fprintf(stderr, "\nThis is not a valid .wav file, invalid chunk length.\n");
- return( FAILURE );
- }
- pcm_ck_len = (((((((uint32)wav_rec[3]) << 8 ) + wav_rec[2] ) << 8 )
- + wav_rec[1]) << 8 ) + wav_rec[0];
-
- fprintf(stderr, "\nMONO 8 bit PCM format. Sampling rate is %lu Hz.\n", sample_rate);
-
- /*
- ** Well, we finally hit the PCM sample data.
- ** This looks like what we wanted, so we will call this success.
- */
-
- return( SUCCESS );
- }
-
- /*****************************************************************************
- ** NAME: process_record()
- **
- ** PURPOSE:
- ** There is data in the count table. This must now be interpreted.
- ** The count values are converted to the data they are representing.
- **
- ** DESCRIPTION:
- ** This function will take data from the count table and interpret it.
- ** Then this data is removed from the buffer to make room for new data.
- ** Data that is not processed when we leave this function is moved towards
- ** the start of the buffer in order to make room for the new data.
- ** We should get here every time a complete record has been stuffed into
- ** the table.
- **
- ** INPUT:
- ** Nothing.
- ** Data is taken from the sample count table.
- **
- ** OUTPUT:
- ** Data is output to the file.
- ** The table is reset to the beginning.
- ** The function returns nothing.
- **
- */
-
- static void process_record( void )
- {
- uint32 bit_cnt; /* Bit counter */
- uint32 bit_len; /* Length of one bit */
- uint32 bit_limit; /* Length for recognizing bit */
- ubyte byte; /* Byte decoded from fsk data */
- uint32 bytes; /* Number of bytes read */
- uint32 checksum; /* Checksum of the record */
- uint32 cnt; /* Count of samples */
- uint32 cnt_sum; /* Total sample counts for byte */
- uint32 ctl_1_cnt; /* Samples in control byte 1 */
- uint32 ctl_2_cnt; /* Samples in control byte 2 */
- uint32 data_ndx; /* Index for record data */
- uint32 ndx; /* Index into buffer */
- uint32 ndx_prwt; /* end of record */
-
- /*
- ** If we only have a mark tone, this must be the leader of the tape.
- ** We should write out the leader to the file, but for now, we will simply
- ** ignore it. It will be written with the first record.
- */
- if( sample_tbl_ndx == 0 )
- return;
-
- bytes = 0;
-
- PRINT( ("\nIn process_record() sample_tbl_ndx = %lu\n", sample_tbl_ndx) );
- PRINT( ("Now cleaning up glitches.\n") );
-
- /*
- ** Output the table to the FSK file and the diagnostics data.
- */
- for( ndx = 0; ndx <= sample_tbl_ndx; ndx++ )
- {
- PRINT( ("ndx %lu Position %lu Mark %lu, Space %lu.\n", ndx,
- sample_cnt_tbl[ndx].sample_pos,
- sample_cnt_tbl[ndx].sample_cnt_mark,
- sample_cnt_tbl[ndx].sample_cnt_space ) );
-
- /*
- ** Output the table to the FSK file.
- ** The last space count was not finished yet, so we will have to print that
- ** the next time we print the table. The last thing we print is the
- ** last mark count, so do not print that the next time. Of course all
- ** this is not applied for the very first and very last time we print
- ** the contents of the table.
- */
- if( fsk )
- {
- if( ndx < sample_tbl_ndx )
- {
- if( ( ndx == 0 ) && ( fsk_print_first == FALSE ) )
- { /* First pair of table */
- fprintf( fsk_file, "%.5lu\n",
- sample_cnt_tbl[ndx].sample_cnt_space );
- }
- else
- { /* First time around or regular pair */
- fprintf( fsk_file, "%.8lu %.5lu %.5lu\n",
- sample_cnt_tbl[ndx].sample_pos,
- sample_cnt_tbl[ndx].sample_cnt_mark,
- sample_cnt_tbl[ndx].sample_cnt_space );
- fsk_print_first = FALSE;
- }
- } /* end if not at end of table */
- else
- { /* Last pair in table */
- if( cnt_cur ) /* Not yet end of file? */
- {
- fprintf( fsk_file, "%.8lu %.5lu ",
- sample_cnt_tbl[ndx].sample_pos,
- sample_cnt_tbl[ndx].sample_cnt_mark );
- }
- else
- { /* end of file, flush all */
- fprintf( fsk_file, "%.8lu %.5lu %.5lu\n",
- sample_cnt_tbl[ndx].sample_pos,
- sample_cnt_tbl[ndx].sample_cnt_mark,
- sample_cnt_tbl[ndx].sample_cnt_space );
- }
- } /* end else if not at end of table */
- } /* end if fsk data requested */
- } /* end for all table entries */
-
- /*
- ** If things worked the way they were designed, we should have one complete
- ** record in the table now. It starts out with the Pre Record Write Tone.
- ** Before we start processing, first clean up glitches.
- ** Mark and space tones that are very short should be ignored. We add their
- ** count to the preceeding count.
- ** Maybe we should first see how many glitches there are, possibly disposing
- ** of this entire record as noise in the leader or PRWT.
- ** Since our record should start out with a very long mark tone, we will
- ** assume that this first mark tone is fine.
- */
- ndx_prwt = sample_tbl_ndx;
-
- for( ndx = 0; ndx < sample_tbl_ndx; )
- {
- if( ndx && ( sample_cnt_tbl[ndx].sample_cnt_mark > sample_cnt_irg ) )
- {
- ndx_prwt = ndx;
- break;
- }
-
- /*
- ** If the current space count is too low, add it, and the next mark count to
- ** the current mark count, move the next space count to the current space
- ** count, and move up the rest of the table.
- ** However, if the next mark count is also too low, add this space count
- ** and the next mark count to the next space count. We can do this by
- ** adding the next mark count and the next space count to the current space
- ** count, and then move up the rest of the table.
- */
- if( sample_cnt_tbl[ndx].sample_cnt_space < sample_cnt_bit_limit )
- {
- if( sample_cnt_tbl[ndx + 1].sample_cnt_mark < sample_cnt_bit_limit )
- {
- sample_cnt_tbl[ndx].sample_cnt_space +=
- sample_cnt_tbl[ndx + 1].sample_cnt_mark +
- sample_cnt_tbl[ndx + 1].sample_cnt_space;
- }
- else
- {
- sample_cnt_tbl[ndx].sample_cnt_mark +=
- sample_cnt_tbl[ndx].sample_cnt_space +
- sample_cnt_tbl[ndx + 1].sample_cnt_mark;
- sample_cnt_tbl[ndx].sample_cnt_space =
- sample_cnt_tbl[ndx + 1].sample_cnt_space;
- }
-
- /*
- ** Move the sample counts after the next one up by one.
- */
- if( ndx + 1 < sample_tbl_ndx )
- {
- memcpy( &(sample_cnt_tbl[ndx + 1]),
- &(sample_cnt_tbl[ndx + 2]),
- (sample_tbl_ndx - ndx - 1) * sizeof(sample_cnt_blk) );
- }
- sample_tbl_ndx--;
- ndx_prwt = sample_tbl_ndx;
- continue; /* Make sure it is fine now */
- }
-
- /*
- ** If the next mark count is too low, add it, and the next space count to
- ** the current space count, and move up the rest of the table.
- */
- if( sample_cnt_tbl[ndx + 1].sample_cnt_mark < sample_cnt_bit_limit )
- {
- sample_cnt_tbl[ndx].sample_cnt_space +=
- sample_cnt_tbl[ndx + 1].sample_cnt_mark +
- sample_cnt_tbl[ndx + 1].sample_cnt_space;
-
- /*
- ** Move the sample counts after the next one up by one.
- */
- if( ndx + 1 < sample_tbl_ndx )
- {
- memcpy( &(sample_cnt_tbl[ndx + 1]),
- &(sample_cnt_tbl[ndx + 2]),
- (sample_tbl_ndx - ndx - 1) * sizeof(sample_cnt_blk) );
- }
- sample_tbl_ndx--;
- ndx_prwt = sample_tbl_ndx;
- continue; /* Make sure it is fine now */
- }
-
- /*
- ** This sample count is fine, move to the next one.
- */
- ndx++;
- }
-
- if( diagnostics )
- {
- printf("Done cleaning up glitches. %lu elements to process.\n", ndx_prwt);
- for( ndx = 0; ndx <= ndx_prwt; ndx++ )
- {
- printf("ndx %lu Position %lu Mark %lu, Space %lu.\n", ndx,
- sample_cnt_tbl[ndx].sample_pos,
- sample_cnt_tbl[ndx].sample_cnt_mark,
- sample_cnt_tbl[ndx].sample_cnt_space );
- }
- }
-
- /*
- ** The table starts with a Pre-Record Write Tone.
- ** A bit is about 73.5 samples if the sample rate is 44.100.
- ** We need 73.5 samples to form a single bit. However, the tape
- ** may not be coded at 600 baud.
- ** We have to allow for some tolerance in the baudrate.
- ** We need to detect the baudrate now.
- ** Each record starts out with two marker bytes with a value of 0x55.
- ** We will use these bytes to detect the baudrate, since that is what they
- ** were intended to be used for.
- ** Note that some tapes have a weird format, in which these two marker bytes
- ** might not be present, so if we do not find them, we cannot be sure that
- ** this stuff is noise in that case.
- */
- if( ndx_prwt < 5 )
- {
-
- /*
- ** Glitch in the PRWT, ignore this stuff.
- */
- bit_len = 1;
- bit_limit = bit_len * 55 / 100;
- }
- else
- if( ndx_prwt < 10 )
- {
-
- /*
- ** Might be one of these weird formats, probably a couple of checksum bytes.
- */
- bit_len = sample_cnt_bit;
- bit_limit = bit_len * 55 / 100;
- }
- else
- {
-
- /*
- ** We should find the two marker bytes at the beginning of the record.
- ** They consist of 10 alternating bits each, so we compute the sum of the
- ** first 20 mark and space counts, which should be 20 bits. If we divide
- ** this sum by 20, we know the length of one bit.
- */
- ctl_1_cnt = sample_cnt_tbl[0].sample_cnt_space +
- sample_cnt_tbl[1].sample_cnt_mark +
- sample_cnt_tbl[1].sample_cnt_space +
- sample_cnt_tbl[2].sample_cnt_mark +
- sample_cnt_tbl[2].sample_cnt_space +
- sample_cnt_tbl[3].sample_cnt_mark +
- sample_cnt_tbl[3].sample_cnt_space +
- sample_cnt_tbl[4].sample_cnt_mark +
- sample_cnt_tbl[4].sample_cnt_space +
- sample_cnt_tbl[5].sample_cnt_mark;
- ctl_2_cnt = sample_cnt_tbl[5].sample_cnt_space +
- sample_cnt_tbl[6].sample_cnt_mark +
- sample_cnt_tbl[6].sample_cnt_space +
- sample_cnt_tbl[7].sample_cnt_mark +
- sample_cnt_tbl[7].sample_cnt_space +
- sample_cnt_tbl[8].sample_cnt_mark +
- sample_cnt_tbl[8].sample_cnt_space +
- sample_cnt_tbl[9].sample_cnt_mark +
- sample_cnt_tbl[9].sample_cnt_space +
- sample_cnt_tbl[10].sample_cnt_mark;
-
- bit_len = ( ctl_1_cnt + ctl_2_cnt ) / 20;
-
- /*
- ** If the bit length gets a strange value, the record probably did not
- ** start with two marker bytes, we will assume the default baudrate.
- */
- if( ( bit_len <= sample_cnt_bit * 70 / 100 ) ||
- ( bit_len >= sample_cnt_bit * 120 / 100 ) )
- bit_len = sample_cnt_bit;
- bit_limit = bit_len * 55 / 100;
- }
-
- PRINT( ("At %.8ld bit length = %lu, baudrate = %lu.\n",
- cnt_total, bit_len, sample_rate / bit_len ) );
-
- if( ( bit_len > sample_cnt_bit * 70 / 100 ) &&
- ( bit_len < sample_cnt_bit * 120 / 100 ) )
- {
- fprintf( stderr,
- "At %.8ld bit length = %lu samples, baudrate = %lu baud.\n",
- cnt_total, bit_len, sample_rate / bit_len );
-
- /*
- ** Write out the data to the cassette file.
- ** Put the length of the PRWT into the aux-bytes.
- */
- memcpy( cas_rec.cas_record_id, "data", 4 );
- cas_rec.cas_len_lo = 0;
- cas_rec.cas_len_hi = 0;
- cas_rec.cas_aux1 = (( sample_cnt_tbl[0].sample_cnt_mark * 1000 ) / sample_rate ) % 256;
- cas_rec.cas_aux2 = (( sample_cnt_tbl[0].sample_cnt_mark * 1000 ) / sample_rate ) / 256;
-
- data_ndx = 0;
-
- for( ndx = 0; ndx < ndx_prwt; )
- {
-
- /*
- ** A byte consists of 8 data bits, a startbit and a stopbit.
- ** See how many bits are represented by the sample count.
- */
- byte = 0x00;
- cnt_sum = 0;
- PRINT( ("Offset %lu ndx %lu ", sample_cnt_tbl[ndx].sample_pos,
- ndx ) );
- for( bit_cnt = 0; bit_cnt < 10; )
- {
- cnt = sample_cnt_tbl[ndx].sample_cnt_space;
- cnt_sum += cnt;
- PRINT( (" %lu ", cnt ) );
- while( cnt > bit_limit )
- {
- if( cnt > bit_len )
- cnt -= bit_len;
- else
- cnt = 0;
- if( bit_cnt ) /* Ignore startbit */
- {
- byte = byte >> 1; /* Make room for next bit */
- byte &= 0x7F; /* Add a zero bit */
- PRINT( ("0") );
- }
- bit_cnt++;
- if( bit_cnt == 10 ) /* Quit when we hit the stopbit */
- break;
- } /* End while processing space count */
- ndx++;
- cnt = sample_cnt_tbl[ndx].sample_cnt_mark;
- cnt_sum += cnt;
- PRINT( (" %lu ", cnt ) );
- while( cnt > bit_limit )
- {
- if( cnt > bit_len )
- cnt -= bit_len;
- else
- cnt = 0;
- if( bit_cnt < 9 ) /* Ignore stopbit */
- {
- byte = byte >> 1; /* Make room for next bit */
- byte |= 0x080; /* Add a one bit */
- PRINT( ("1") );
- }
- bit_cnt++;
- if( bit_cnt == 10 ) /* Quit when we hit the stopbit */
- break;
- } /* End while processing mark count */
- } /* End for 10 bits */
- PRINT( ("\nByte %.2x sum %lu.\n", byte, cnt_sum ) );
- cas_rec.cas_data[data_ndx++] = byte;
- bytes++;
- } /* end for all pairs up to next PRWT */
-
- cas_rec.cas_len_hi = data_ndx / 256;
- cas_rec.cas_len_lo = data_ndx % 256;
- fwrite( &cas_rec, 1,
- cas_rec.cas_len_hi * 256 + cas_rec.cas_len_lo + 8, cas_file );
-
- /*
- ** Print the hex values.
- ** Start out with the PRWT length and the record length.
- */
- fprintf( hex_file, "%.5lu %lu",
- ( sample_cnt_tbl[0].sample_cnt_mark * 1000 ) / sample_rate, bytes );
- checksum = 0;
- for( ndx = 0; ndx < data_ndx; ndx++ )
- {
- fprintf( hex_file, " %.2x", cas_rec.cas_data[ndx] );
- if( ndx < data_ndx - 1 )
- {
- checksum += cas_rec.cas_data[ndx];
- if( checksum > 0x0ff ) /* If carry */
- {
- checksum &= 0x0ff; /* Wrap around */
- checksum++; /* Add carry back in */
- }
- }
- } /* end for all bytes in the block */
- fprintf( hex_file, " %.2lx %s\n", checksum,
- ( checksum == cas_rec.cas_data[data_ndx - 1] ) ? "ok" : "bad" );
-
- if( diagnostics )
- {
- if( checksum != cas_rec.cas_data[data_ndx - 1] )
- printf("\nBad checksum!\n");
- printf( "PRWT is %lu milliseconds.\n", sample_cnt_tbl[0].sample_cnt_mark / 44 );
- }
-
- /*
- ** Move the remaining portion of the buffer to the beginning of the buffer.
- ** Cleaning up the table might have caused the PRWT to be not the last
- ** element in the table, so take note of this when moving the table.
- */
- if( sample_tbl_ndx )
- {
- if( sample_tbl_ndx > ndx_prwt )
- {
- ndx = sample_tbl_ndx - ndx_prwt + 1;
- memcpy( &(sample_cnt_tbl[0]),
- &(sample_cnt_tbl[ndx_prwt]),
- sizeof(sample_cnt_blk) * ndx);
- sample_tbl_ndx = ndx - 1;
- }
- else
- {
- memcpy( &(sample_cnt_tbl[0]),
- &(sample_cnt_tbl[sample_tbl_ndx]),
- sizeof(sample_cnt_blk) );
- sample_tbl_ndx = 0;
- }
- }
- } /* end if baudrate acceptable */
- else
- {
- fprintf( stderr,
- "At %.8ld skipping noise or bad data.\n",
- cnt_total );
-
- /*
- ** Must have been noise, add it all and consider it prwt.
- */
- if( sample_tbl_ndx )
- {
- for( ndx = 0; ndx < ndx_prwt; ndx++ )
- {
- sample_cnt_tbl[ndx_prwt].sample_cnt_mark +=
- sample_cnt_tbl[ndx].sample_cnt_mark +
- sample_cnt_tbl[ndx].sample_cnt_space;
- }
- ndx = sample_tbl_ndx - ndx_prwt + 1;
- memcpy( &(sample_cnt_tbl[0]),
- &(sample_cnt_tbl[ndx_prwt]),
- sizeof(sample_cnt_blk) * ndx);
- sample_tbl_ndx = 0;
- }
- }
-
- PRINT( ("Leaving process_record() with %lu bytes processed.\n", bytes ) );
-
- }
-
- /*****************************************************************************
- ** NAME: replenish_buffer()
- **
- ** PURPOSE:
- ** Keep the buffer filled with PCM data.
- **
- ** DESCRIPTION:
- ** This function will read data from the wave file and store it in the
- ** PCM buffer. Data that was still left in the buffer is moved towards
- ** the start of the buffer in order to make room for the new data.
- **
- ** INPUT:
- ** Nothing.
- ** Data is read from the wave file.
- **
- ** OUTPUT:
- ** Data is stored in the buffer.
- ** Buffer status is updated.
- ** The function returns nothing.
- **
- */
-
- static void replenish_buffer( void )
- {
- uint32 bytes; /* Number of bytes read */
- uint32 rest_len; /* Remaining bytes in buffer */
- ubyte wav_rec[PCM_BUF_HALF]; /* Buffer for reading wave data */
-
- /*
- ** Replenish buffer.
- ** Move the remaining portion of the buffer to the beginning of the buffer.
- ** The buffer end points to just beyond the last byte of the buffer.
- */
- if( pcm_ndx && pcm_ndx_end )
- {
- if( pcm_ndx > pcm_ndx_end )
- {
- fprintf( stderr, "\nPanic: Beyond end of buffer.\n");
- getchar();
- }
- else
- {
- rest_len = pcm_ndx_end - pcm_ndx;
- memcpy( pcm, &pcm[pcm_ndx], rest_len );
- pcm_ndx = 0;
- pcm_ndx_end = rest_len;
- }
- }
-
- /*
- ** Get some more bytes and stuff them into the PCM buffer.
- */
- bytes = PCM_BUF_HALF;
- bytes = fread( (char *)wav_rec, (int)1, (int)bytes, wav_file );
- if( bytes )
- {
- memcpy( &pcm[pcm_ndx_end], wav_rec, bytes );
- pcm_ndx_end += bytes;
- pcm_bytes += bytes;
- }
- }
-
- /*****************************************************************************
- ** NAME: usage()
- **
- ** PURPOSE:
- ** Display the command line format for the program.
- **
- ** DESCRIPTION:
- ** This function will explain the usage of the program to the user.
- ** The program name is taken from the first command line argument.
- **
- ** INPUT:
- ** - The address of the command line, containing the program name.
- **
- ** OUTPUT:
- ** The usage is displayed on the terminal.
- ** The function returns nothing.
- **
- */
-
- static void usage( cmd )
- char * cmd; /* Program name */
- {
- char * whoami; /* For searching program name in command line */
- char * name; /* Pointer to actual program name in command */
- int len; /* Length of program name */
- int found_dot; /* Nonzero if we found a dot in the name */
-
- /*
- ** Get program name and print usage message.
- ** The complete pathname including extension is part of the first
- ** argument as passed by the operating system.
- */
- for( whoami = cmd, len = 0, found_dot = 0; *whoami; whoami++ )
- {
- if( *whoami == '.' )
- {
- found_dot = 1;
- continue;
- }
- if( *whoami == '\\' ) /* if this was part of the path, */
- {
- name = whoami + 1; /* record position */
- len = 0; /* then restart counting length */
- found_dot = 0;
- continue;
- }
- if( *whoami == ' ' ) /* end of name found */
- break;
- if( found_dot ) /* skip .exe or .com stuff */
- continue;
- len++; /* Increment program name length */
- }
-
- /*
- ** Let me explain...
- */
- fprintf(stderr, "\nUsage: %.*s [wavefile] [\"description\"] [/d] [/f]\n", len, name);
- fprintf(stderr, "to convert a .wav file to a .cas cassette image.\n\n");
- fprintf(stderr, "wavefile an Atari classic tape sampled at 44.100.\n");
- fprintf(stderr, "description descriptive text entered as a quoted string.\n\n");
- fprintf(stderr, "/d to print diagnostic information.\n");
- fprintf(stderr, "/f to write the FSK table file.\n");
- fprintf(stderr, "Refer to the documentation for more information.\n");
-
- return;
- }
-
- /*****************************************************************************
- ** NAME: wav2fsk()
- **
- ** PURPOSE:
- ** Read data from the .wav file and convert it to levels recognized
- ** as fsk mark and space values.
- ** The number of samples within one half period is counted. Based on
- ** this, we can determine the frequency of the sound, and thus we can
- ** distinguish between mark and space levels. The output routine is
- ** then called to print this number of samples.
- ** The number of samples of this level are recorded for interpretation.
- ** If we have a complete record in the buffer, we can try to interpret
- ** the bits in the buffer.
- **
- ** DESCRIPTION:
- ** This function will read the data and process it.
- **
- ** INPUT:
- ** Nothing.
- **
- ** OUTPUT:
- ** Prints results.
- ** Returns SUCCESS if data converted successfully.
- ** Returns FAILURE if some error occurred.
- **
- */
-
- static uint32 wav2fsk( void )
- {
- uint16 level; /* Interpreted level of signal */
-
- cnt_total = 0;
-
- /*
- ** Set pointers to point to the end of the buffer.
- */
- pcm_cnt = 0;
- pcm_ndx = 0;
- pcm_ndx_end = 0;
-
- /*
- ** Initialize sample count table.
- */
- sample_tbl_ndx = 0;
- sample_tbl_level = FSK_MARK;
- sample_cnt_tbl[0].sample_pos = 0;
- sample_cnt_tbl[0].sample_cnt_mark = 0;
-
- /*
- ** Load the buffer.
- */
- replenish_buffer();
- replenish_buffer();
-
- if( pcm[1] > pcm[0] )
- {
- pcm_level_previous = 0;
- pcm_level_rising = TRUE;
- }
- else
- {
- pcm_level_previous = 255;
- pcm_level_rising = FALSE;
- }
-
- period_sample_cnt();
- period_sample_cnt();
- while( cnt_cur )
- {
- if( ( cnt_cur >= sample_cnt_low ) && ( cnt_cur <= sample_cnt_high ) )
- level = FSK_SPACE;
- else
- level = FSK_MARK;
-
- process_cnt( cnt_val, level );
-
- period_sample_cnt();
- } /* end while */
- process_record();
- printf("\n");
-
- return( SUCCESS );
- }
-
- /*****************************************************************************
- == EXPORTED FUNCTIONS
- *****************************************************************************/
-
- /*****************************************************************************
- ** NAME: MAIN()
- **
- ** PURPOSE:
- ** An entry point for testing or running this utility.
- **
- ** DESCRIPTION:
- ** Prompt for the file to open and then go process it.
- **
- ** INPUT:
- ** argc and argv.
- **
- ** OUTPUT:
- ** Returns an int as it should.
- **
- */
- int main( argc, argv )
- int argc; /* Command line argument count */
- char * argv[]; /* Command line argument ptrs */
- {
- ubyte answer; /* Response to yes/no question */
- uint32 arg_ndx; /* Argument number index */
- uint32 arg_no; /* Argument number */
- uint32 wrk_ndx; /* Work index */
- ubyte desc[80]; /* Description of cassette tape */
- uint16 desc_len; /* Length of the description */
- bool end_of_str; /* Null terminator seen? */
- ubyte input_path[PATH_LEN]; /* Input wave file spec */
- ubyte fsk_path[PATH_LEN]; /* Output fsk file spec */
- ubyte hex_path[PATH_LEN]; /* Output hex file spec */
- ubyte cas_path[PATH_LEN]; /* Output cas file spec */
- ubyte buf[BUF_LEN]; /* Buffer string */
- uint32 stat; /* Status from function */
- ubyte proceed; /* Proceed with conversion */
-
- /*
- ** Allocate buffer space for the sample count table.
- */
- sample_cnt_tbl = (sample_cnt_blk *)
- malloc((unsigned long)SAMPLE_CNT_TBL_LEN *
- sizeof( sample_cnt_blk ) );
-
-
- if( !sample_cnt_tbl )
- {
- fprintf( stderr, "\nCannot allocate buffer, insufficient memory.\n" );
- exit( 255 );
- }
-
- /*
- ** Process command line arguments.
- ** We do not treat the options switch as an argument. It may be placed
- ** anywhere on the command line. So we have to count the arguments ourselves
- ** so that we know what argument we are processing.
- */
- arg_no = 0;
- diagnostics = FALSE;
- fsk = FALSE;
- desc_len = 0;
-
- for( arg_ndx = 1; arg_ndx < argc; arg_ndx++ )
- {
-
- /*
- ** If we encounter the options switch, process the options.
- ** The options must start with a slash.
- */
- if( argv[arg_ndx][0] == '/' )
- {
-
- for( wrk_ndx = 0; argv[arg_ndx][wrk_ndx]; wrk_ndx++ )
- {
-
- /*
- ** If the user is confused, seeking help, she/he should read the * manual.
- ** We can give them a hint though.
- */
- if( argv[arg_ndx][wrk_ndx] == '?' )
- {
- usage( argv[0] );
- exit( 0 );
- }
-
- /*
- ** The /d option selects the diagnostics output.
- */
- if( toupper( argv[arg_ndx][wrk_ndx] ) == 'D' )
- {
- diagnostics = TRUE;
- continue;
- }
-
- /*
- ** The /f option selects the fsk table output.
- */
- if( toupper( argv[arg_ndx][wrk_ndx] ) == 'F' )
- {
- fsk = TRUE;
- continue;
- }
-
- /*
- ** Ignore other options.
- */
- continue;
- } /* end for all characters after options switch */
-
- /*
- ** No further processing for the options switches.
- */
- continue;
- } /* end if options switch */
- arg_no++;
-
- /*
- ** First argument is the file spec.
- */
- if( arg_no == 1 )
- {
- for ( wrk_ndx = 0, end_of_str = FALSE;
- wrk_ndx < PATH_LEN; wrk_ndx++ )
- {
- if ( argv[arg_ndx][wrk_ndx] == '\0' ) /* End of argument string? */
- end_of_str = TRUE;
- if ( end_of_str )
- input_path[wrk_ndx] = '\0';
- else
- input_path[wrk_ndx] = toupper( argv[arg_ndx][wrk_ndx] );
- }
-
- wav_file = fopen( (char *)input_path, "rb" );
- if( wav_file == NULL )
- {
- fprintf(stderr, "Cannot open wave file %s\n", input_path);
- exit( 255 );
- }
- }
-
- /*
- ** Optionally, the description can be entered as the second command line
- ** argument. This should be done as a quoted string, since that is the
- ** way command line arguments work.
- */
- if( arg_no == 2 )
- {
- desc_len = STRLEN( argv[arg_ndx] );
- if( desc_len > 80 )
- desc_len = 80;
- memcpy( desc, argv[arg_ndx], desc_len );
- } /* end if description argument */
- } /* end for all command line arguments */
-
- /*
- ** If there is no filename on the command line, ask for it.
- */
- if( arg_no == 0 )
- {
-
- /*
- ** Open hailing frequencies.
- ** No command line arguments, so ask what it is we have to do.
- */
- printf( "Classic Atari cassette tape recovery version April 20, 1997\n" );
- printf( "Copyright 1996, 1997 by Ernest R. Schreurs. All rights reserved.\n" );
- printf( "Amiga port by Wojciech Pasiecznik (voydial@wp.pl).\n" );
-
-
- while( TRUE ) /* until terminated by control C*/
- {
- printf( "\nEnter ^C or hit Control C to terminate\n" );
-
- do /* until .wav file entered */
- {
- printf("\nEnter .wav file to be converted : ");
- GET_BUF();
-
- for ( wrk_ndx = 0, end_of_str = FALSE;
- wrk_ndx < PATH_LEN; wrk_ndx++ )
- {
- if ( wrk_ndx < BUF_LEN )
- {
- if ( buf[wrk_ndx] == '\n' ) /* End of inputted string? */
- end_of_str = TRUE;
- if ( buf[wrk_ndx] == '\0' ) /* Overkill, End marked by \n */
- end_of_str = TRUE;
- if ( end_of_str )
- input_path[wrk_ndx] = '\0';
- else
- input_path[wrk_ndx] = toupper( buf[wrk_ndx] );
- }
- }
- } while ( input_path[0] == ' ' );
-
- do /* until answer is Y or N */
- {
- printf("\nLoading file %s\n", input_path);
- printf("\nIs this correct Y)es or N)o : ");
- GET_BUF();
- proceed = toupper( buf[0] );
-
- /*
- ** If blank, default is correct
- */
- if ( proceed == '\n' )
- proceed = 'Y';
-
- } while ( proceed != 'Y' && proceed != 'N' );
-
- if ( proceed == 'N' )
- continue;
-
- do /* until answer is Y or N */
- {
- printf("\nPrint diagnostic data Y)es or N)o : ");
- GET_BUF();
- answer = toupper( buf[0] );
-
- /*
- ** If blank, default is correct
- */
- if ( answer == '\n' )
- answer = 'Y';
-
- } while ( answer != 'Y' && answer != 'N' );
-
- diagnostics = ( answer == 'Y' ) ? TRUE : FALSE;
-
- printf( "\nLoading data from wave file.\n" );
-
- wav_file = fopen( (char *)input_path, "rb" );
- if( wav_file == NULL )
- {
- fprintf(stderr, "Cannot open wave file\n");
- continue;
- }
- break;
- } /* end while need a valid filename */
-
- printf("\nEnter description : ");
- GET_BUF();
-
- for ( wrk_ndx = 0, desc_len = 0, end_of_str = FALSE;
- wrk_ndx < 80; wrk_ndx++ )
- {
- if ( wrk_ndx < BUF_LEN )
- {
- if ( buf[wrk_ndx] == '\n' ) /* End of inputted string? */
- end_of_str = TRUE;
- if ( buf[wrk_ndx] == '\0' ) /* Overkill, End marked by \n */
- end_of_str = TRUE;
- }
- if ( end_of_str )
- desc[wrk_ndx] = '\0';
- else
- {
- desc[wrk_ndx] = buf[wrk_ndx];
- desc_len++;
- }
- }
- } /* end else if command line arguments */
-
- /*
- ** Process the header of the .wav file.
- */
- stat = process_header();
- if( stat == FAILURE )
- exit( 255 );
-
- PRINT( ("File : %s\n", input_path ) );
-
- memcpy( fsk_path, input_path, PATH_LEN );
- memcpy( &(fsk_path[STRLEN(fsk_path) - 3]), "fsk", 3 );
- memcpy( hex_path, input_path, PATH_LEN );
- memcpy( &(hex_path[STRLEN(hex_path) - 3]), "hex", 3 );
- memcpy( cas_path, input_path, PATH_LEN );
- memcpy( &(cas_path[STRLEN(cas_path) - 3]), "cas", 3 );
-
- if( fsk )
- fsk_file = fopen( (char *)fsk_path, "w" );
- hex_file = fopen( (char *)hex_path, "w" );
- cas_file = fopen( (char *)cas_path, "wb" );
-
- /*
- ** Write the header to the cassette file. The header makes it possible
- ** to identify the file as a .cas file. Also, the description is stored
- ** in this header record.
- */
- memcpy( cas_rec.cas_record_id, "FUJI", 4 );
- cas_rec.cas_len_lo = desc_len;
- cas_rec.cas_len_hi = desc_len / 256;
- cas_rec.cas_aux1 = 0x00;
- cas_rec.cas_aux2 = 0x00;
- if( desc_len )
- memcpy( cas_rec.cas_data, desc, desc_len );
- fwrite( &cas_rec, 1, cas_rec.cas_len_hi * 256 + cas_rec.cas_len_lo + 8, cas_file );
-
- /*
- ** Write out default baud rate to the cassette file.
- */
- memcpy( cas_rec.cas_record_id, "baud", 4 );
- cas_rec.cas_len_lo = 0;
- cas_rec.cas_len_hi = 0;
- cas_rec.cas_aux1 = 600 % 256;
- cas_rec.cas_aux2 = 600 / 256;
- fwrite( &cas_rec, 1, 8, cas_file );
-
-
- if( fsk )
- fprintf( fsk_file, "%.*s\n", desc_len, desc );
- fprintf( hex_file, "%.*s\n", desc_len, desc );
- fsk_print_first = TRUE;
-
- /*
- ** Process the data portion of the .wav file.
- */
- stat = wav2fsk();
-
- cleanup();
-
- fprintf(stderr, "\nDone processing.\n");
-
- return 0;
- }
-
- /*****************************************************************************
- ** MODIFICATION HISTORY
- **
- ** DATE BY Description
- ** ---------- --- ---------------------------------------------------------
- ** 1996/11/30 ERS Project start
- ** 1997/05/01 ERS Release 01.00
- **
- *****************************************************************************/
-